package com.oxygen.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.FieldAnalysisRequest;
import org.apache.solr.client.solrj.response.AnalysisResponseBase.AnalysisPhase;
import org.apache.solr.client.solrj.response.AnalysisResponseBase.TokenInfo;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.FieldAnalysisResponse;
import org.apache.solr.client.solrj.response.FieldAnalysisResponse.Analysis;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.TermsResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.TermsParams.TermsRegexpFlag;

import com.oxygen.dto.Pagination;
import com.oxygen.dto.SearchRequest;
import com.oxygen.dto.SearchResponse;

/**
 * solr服务
 * 
 * @author Daniel
 * @version 1.0 <br>
 *          date: 2013-5-29 下午3:13:12 <br>
 *          modify: 2013-5-29 下午3:13:12 <br>
 */
public abstract class AbstractSolrService extends SuperServiceImpl {
	private static final Logger log = Logger.getLogger(AbstractSolrService.class);
	public static final String DEFAULT_FIELD_TYPE = "text_ik";

	/**
	 * 执行搜索
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:12:47 <br>
	 *          modify: 2013-5-30 下午5:12:47 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @param clazz
	 * @param searchRequest
	 * @return
	 */
	protected <E> SearchResponse<E> executeSearch(SolrServer solrServer, Class<E> clazz, SearchRequest searchRequest) {
		SearchResponse<E> searchResponse = new SearchResponse<E>();
		try {
			SolrQuery query = new SolrQuery();
			long pageNo = searchRequest.getP();
			long pageSize = searchRequest.getPageSize();
			long start = (pageNo - 1) * pageSize;
			long rows = searchRequest.getPageSize();
			Map<String, String> orderBy = searchRequest.getOrderBy();
			String keyword = searchRequest.getQ();
			String criteria = searchRequest.getCriteria();
			String criteriaFilter = searchRequest.getCriteriaFilter();
			String[] fields = searchRequest.getFields();
			String[] highlightFields = searchRequest.getHighlightFields();
			String[] facetFields = searchRequest.getFacetFields();
			// // 设置分页
			// if (rows > 20) {
			// rows = 20;// 每页显示记录数最大值
			// }
			query.setStart((int) start);
			query.setRows((int) rows);
			log.info(criteria + ",orderBy:" + orderBy);
			if (criteria != null && !"".equals(criteria.trim())) {// 不允许搜索所有记录
				// 设置搜索条件
				query.setQuery(criteria);
			}
			if (criteriaFilter != null && !"".equals(criteriaFilter.trim())) {
				// 设置过滤条件
				query.setFilterQueries(criteriaFilter);
			}
			// 设置搜索结果，如果设置了则只返回几个字段，否则返回所有
			if (fields != null && fields.length > 0) {
				query.setFields(fields);
			}
			// 设置排序
			if (orderBy != null && !orderBy.isEmpty()) {
				for (Map.Entry<String, String> entry : orderBy.entrySet()) {
					query.setSort(entry.getKey(), SolrQuery.ORDER.valueOf(entry.getValue()));
				}
			}
			// 设置高亮
			if (highlightFields != null && highlightFields.length > 0) {
				query.setHighlight(true);
				query.setHighlightSnippets(3);
				query.setParam("hl.mergeContiguous", "true");
				query.setParam("hl.fl", highlightFields);
			}
			// 设置分组
			if (facetFields != null && facetFields.length > 0) {
				query.setFacet(true);
				query.setFacetMinCount(1);
				query.addFacetField(facetFields);
				query.setFacetLimit(10000);
			}

			QueryResponse queryResponse = this.getQueryResponse(solrServer, query);
			if (queryResponse != null && queryResponse.getStatus() == 0) {// 查询响应成功
				searchResponse.setOrderBy(orderBy);
				searchResponse.setQ(keyword == null ? "" : keyword);
				searchResponse.setCriteria(criteria);
				searchResponse.setQtime(queryResponse.getQTime());

				long numFound = queryResponse.getResults().getNumFound();
				Pagination<E> paginationBean = new Pagination<E>(pageNo, pageSize);
				paginationBean.setNumFound(numFound);
				searchResponse.setPagination(paginationBean);

				List<E> docs = queryResponse.getBeans(clazz);
				searchResponse.setDocs(docs);

				if (highlightFields != null && highlightFields.length > 0) {
					searchResponse.setHighLight(queryResponse.getHighlighting());
				}

				if (facetFields != null && facetFields.length > 0) {
					searchResponse.setFacetMap(buildFacetResult(queryResponse.getFacetFields()));
				}
			}
		} catch (Exception e) {
			log.error("executeSearch Exception", e);
			e.printStackTrace();
		}
		return searchResponse;
	}

	/**
	 * 封装分组搜索的结果
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:12:23 <br>
	 *          modify: 2013-5-30 下午5:12:23 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param facetFieldList
	 * @return
	 */
	private Map<String, Map<String, Long>> buildFacetResult(List<FacetField> facetFieldList) {
		Map<String, Map<String, Long>> facetMap = new LinkedHashMap<String, Map<String, Long>>();
		if (facetFieldList != null && facetFieldList.size() > 0) {
			for (FacetField facetField : facetFieldList) {
				if (facetField != null) {
					String fieldName = facetField.getName();
					List<Count> countList = facetField.getValues();
					if (countList != null && countList.size() > 0) {
						long allCount = 0;
						Map<String, Long> tempFieldValueMap = new LinkedHashMap<String, Long>();
						for (Count c : countList) {
							if (c != null) {
								String label = c.getName();
								long count = c.getCount();
								tempFieldValueMap.put(label, count);
								allCount += count;
							}
						}
						Map<String, Long> fieldValueMap = new LinkedHashMap<String, Long>();
						fieldValueMap.put("ALL", allCount);
						fieldValueMap.putAll(tempFieldValueMap);
						if (fieldValueMap != null && fieldValueMap.size() > 0) {
							facetMap.put(fieldName, fieldValueMap);
						}
					}
				}
			}
		}
		return facetMap;
	}

	/**
	 * 获取搜索结果
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:12:00 <br>
	 *          modify: 2013-5-30 下午5:12:00 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @param query
	 * @return
	 */
	protected QueryResponse getQueryResponse(SolrServer solrServer, SolrQuery query) {
		QueryResponse queryResponse = null;
		try {
			queryResponse = solrServer.query(query);
		} catch (Exception e) {
			log.error("getQueryResponse Exception", e);
		} finally {
			this.closeConnection(solrServer);
		}
		return queryResponse;
	}

	protected List<TermsResponse.Term> terms(SolrServer solrServer, String termsFieldName, String keyword, int limit) {
		SolrQuery query = new SolrQuery();
		query.set("qt", "/terms");
		query.set("terms.fl", termsFieldName);
		query.setTerms(true);
		query.setTermsLimit(limit);
		// query.setTermsPrefix(keyword);
		query.setTermsRegex(".*" + keyword + ".*");
		query.setTermsRegexFlag(TermsRegexpFlag.CASE_INSENSITIVE.name().toLowerCase());

		QueryResponse queryResponse = getQueryResponse(solrServer, query);
		if (queryResponse != null && queryResponse.getStatus() == 0) {// 查询响应成功
			TermsResponse termsResponse = queryResponse.getTermsResponse();
			if (termsResponse != null) {
				Map<String, List<TermsResponse.Term>> termsMap = termsResponse.getTermMap();
				for (Map.Entry<String, List<TermsResponse.Term>> termsEntry : termsMap.entrySet()) {
					List<TermsResponse.Term> termList = termsEntry.getValue();
					return termList;
				}
			}
		}
		return null;
	}

	//
	// protected String suggest(SolrServer solrServer, String keyword) {
	// SolrQuery query = new SolrQuery();
	// query.set("qt", "/suggest");
	// query.set("q", keyword);
	// // query.set("spellcheck.build", "true");
	// StringBuilder buf = new StringBuilder();
	// QueryResponse queryResponse = getQueryResponse(solrServer, query);
	// if (queryResponse != null && queryResponse.getStatus() == 0) {// 查询响应成功
	// SpellCheckResponse spellCheckResponse = queryResponse.getSpellCheckResponse();
	// if (spellCheckResponse != null) {
	// Map<String, Suggestion> suggestedMap = spellCheckResponse.getSuggestionMap();
	// if (suggestedMap != null && suggestedMap.get(keyword) != null) {
	// Suggestion suggestion = suggestedMap.get(keyword);
	// List<String> suggestList = suggestion.getAlternatives();
	// int i = 0;
	// boolean addNewLine = false;
	// Set<String> suggestWordSet = new HashSet<String>();
	// for (String s : suggestList) {
	// if (suggestWordSet.size() > 10) {
	// break;
	// }
	// if (s != null && !"".equals(s)) {
	// String[] tempArr = s.split("---");
	// if (tempArr != null && tempArr.length > 0) {
	// String tempS = tempArr[tempArr.length - 1];
	// if (tempS != null && !"".equals(tempS.trim())) {
	// tempS = tempS.trim().replaceAll(" ", "");
	// if (suggestWordSet.add(tempS)) {
	// buf.append(tempS);
	// addNewLine = true;
	// }
	// }
	// }
	// }
	// if (i != suggestList.size() - 1 && addNewLine) {
	// buf.append("\n");
	// }
	// i++;
	// }
	// return buf.toString();
	// }
	// }
	// }
	// return "";
	// }

	/**
	 * 分词
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:11:45 <br>
	 *          modify: 2013-5-30 下午5:11:45 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @param content
	 * @return
	 */
	protected String tokenize(SolrServer solrServer, String content) {
		List<String> fieldTypeList = new ArrayList<String>();
		fieldTypeList.add(DEFAULT_FIELD_TYPE);
		FieldAnalysisRequest req = new FieldAnalysisRequest();
		req.setFieldTypes(fieldTypeList);
		req.setFieldValue(content);
		FieldAnalysisResponse fieldAnalysisResponse = null;
		StringBuilder txtBuf = new StringBuilder();
		try {
			fieldAnalysisResponse = req.process(solrServer);
			Analysis ans = fieldAnalysisResponse.getFieldTypeAnalysis(DEFAULT_FIELD_TYPE);
			Iterable<AnalysisPhase> iterable = ans.getIndexPhases();
			Iterator<AnalysisPhase> analysisPhaseIterator = iterable.iterator();
			Set<String> keywordSet = new HashSet<String>();
			while (analysisPhaseIterator.hasNext()) {
				AnalysisPhase analysisPhase = analysisPhaseIterator.next();
				List<TokenInfo> tokenInfoList = analysisPhase.getTokens();
				int i = 0;
				for (TokenInfo tokenInfo : tokenInfoList) {
					if (tokenInfo != null && tokenInfo.getText() != null && tokenInfo.getText().trim().length() > 1) {
						if (keywordSet.add(tokenInfo.getText())) {// 关键字去重
							txtBuf.append(tokenInfo.getText());
							if (i != tokenInfoList.size() - 1) {
								txtBuf.append(",");
							}
						}
					}
					i++;
				}
			}
		} catch (Exception e) {
			log.error("tokenizer Exception", e);
		} finally {
			this.closeConnection(solrServer);
		}
		return txtBuf.toString();
	}

	/**
	 * 创建索引
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:11:33 <br>
	 *          modify: 2013-5-30 下午5:11:33 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @param beans
	 * @return
	 */
	protected boolean addBeansToIndex(SolrServer solrServer, Collection<?> beans) {
		boolean retFlag = false;
		try {
			UpdateResponse rsp = solrServer.addBeans(beans);
			if (rsp != null && rsp.getStatus() == 0) {
				rsp = solrServer.commit();
				if (rsp != null && rsp.getStatus() == 0) {
					retFlag = true;
				}
			}
		} catch (Exception e) {
			log.error("addBeansToIndex Exception", e);
			e.printStackTrace();
		} finally {
			this.closeConnection(solrServer);
		}
		return retFlag;
	}

	/**
	 * 创建索引
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:11:12 <br>
	 *          modify: 2013-5-30 下午5:11:12 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @param docs
	 * @return
	 */
	protected boolean addDocumentsToIndex(SolrServer solrServer, Collection<SolrInputDocument> docs) {
		boolean retFlag = false;
		try {
			UpdateResponse rsp = solrServer.add(docs);
			if (rsp != null && rsp.getStatus() == 0) {
				rsp = solrServer.commit();
				if (rsp != null && rsp.getStatus() == 0) {
					retFlag = true;
				}
			}
		} catch (Exception e) {
			log.error("addDocumentsToIndex Exception", e);
			e.printStackTrace();
		} finally {
			this.closeConnection(solrServer);
		}
		return retFlag;
	}

	/**
	 * 删除全部索引
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:11:00 <br>
	 *          modify: 2013-5-30 下午5:11:00 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @return
	 */
	protected boolean deleteAllIndex(SolrServer solrServer) {
		boolean retFlag = false;
		if (solrServer != null) {
			try {
				UpdateResponse rsp = solrServer.deleteByQuery("*:*");
				if (rsp != null && rsp.getStatus() == 0) {
					rsp = solrServer.commit();
					if (rsp != null && rsp.getStatus() == 0) {
						retFlag = true;
					}
				}
			} catch (Exception e) {
				log.error("deleteAllIndex Exception", e);
				e.printStackTrace();
			} finally {
				this.closeConnection(solrServer);
			}
		}
		return retFlag;
	}

	/**
	 * 优化索引
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:10:45 <br>
	 *          modify: 2013-5-30 下午5:10:45 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 * @return
	 */
	protected boolean optimizeIndex(SolrServer solrServer) {
		boolean retFlag = false;
		if (solrServer != null) {
			UpdateResponse rsp = null;
			try {
				rsp = solrServer.optimize();
			} catch (Exception e) {
				log.error("optimizeIndex Exception", e);
				e.printStackTrace();
			} finally {
				this.closeConnection(solrServer);
			}
			if (rsp != null && rsp.getStatus() == 0) {
				retFlag = true;
			}
		}
		return retFlag;
	}

	/**
	 * 回滚对索引的操作
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:10:09 <br>
	 *          modify: 2013-5-30 下午5:10:09 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 */
	protected void rollbackIndex(SolrServer solrServer) {
		if (solrServer != null) {
			try {
				solrServer.rollback();
			} catch (Exception e) {
				log.error("rollbackIndex Exception", e);
				e.printStackTrace();
			} finally {
				this.closeConnection(solrServer);
			}
		}
	}

	/**
	 * 断开solr服务端连接
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:09:15 <br>
	 *          modify: 2013-5-30 下午5:09:15 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServer
	 */
	private void closeConnection(SolrServer solrServer) {
		if (solrServer != null) {
			try {
				solrServer.shutdown();
			} catch (Exception e) {
				log.error("closeConnection Exception", e);
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取solr服务端连接
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:09:06 <br>
	 *          modify: 2013-5-30 下午5:09:06 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param zookeeperHosts
	 * @param solrCollectionName
	 * @return
	 */
	protected SolrServer getSolrServer(String zookeeperHosts, String solrCollectionName) {
		CloudSolrServer server = null;
		try {
			server = new CloudSolrServer(zookeeperHosts);
			server.setDefaultCollection(solrCollectionName);
		} catch (Exception e) {
			log.error("getSolrServer Exception", e);
			e.printStackTrace();
		}
		return server;
	}

	/**
	 * 获取solr服务端连接
	 * 
	 * @author Daniel
	 * @version 1.0 <br>
	 *          date: 2013-5-30 下午5:08:35 <br>
	 *          modify: 2013-5-30 下午5:08:35 <br>
	 *          <h1>example:</h1> <br>
	 *          请在这里添加使用例子
	 * @param solrServerUrl
	 * @return
	 */
	protected SolrServer getSolrServer(String solrServerUrl) {
		HttpSolrServer server = null;
		try {
			server = new HttpSolrServer(solrServerUrl);
			server.setConnectionTimeout(15000);
			server.setSoTimeout(15000);
		} catch (Exception e) {
			log.error("getSolrServer Exception", e);
			e.printStackTrace();
		}
		return server;
	}
}
